package org.lgiavedoni.android.franq.util.phone;

import java.io.IOException;

import org.lgiavedoni.android.franq.service.config.ConfigService;
import org.lgiavedoni.android.franq.service.config.ConfigService.ConfigKey;
import org.lgiavedoni.android.franq.service.log.Logger;
import org.lgiavedoni.android.franq.service.phone.ContextService;
import org.lgiavedoni.android.franq.util.thread.ThreadUtil;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.Intent;
import android.os.Bundle;

import com.google.api.client.apache.ApacheHttpTransport;
import com.google.api.client.googleapis.GoogleHeaders;
import com.google.api.client.googleapis.GoogleTransport;
import com.google.api.client.googleapis.auth.clientlogin.ClientLogin;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.HttpResponseException;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.xml.atom.AtomParser;

public class AccountUtil {

	private static final String AUTH_TOKEN_TYPE = "cl";
	private static HttpTransport transport;
	private static String authToken;
	private static final int REQUEST_AUTHENTICATE = 0;

	private static Account getUserAccount() {
		AccountManager mgr = AccountManager.get(ContextService.inst.getApplicationContext());
		Account[] accts = mgr.getAccountsByType("com.google");
		if (accts != null && accts.length > 0)
			return accts[0];
		return null;
	}

	public static String getUserEmail() {
		return ContextService.inst.isApplicationContextLoaded() && getUserAccount() != null ? getUserAccount().name : ConfigService.inst.getValue(ConfigKey.USER_DEFAULT_ACCOUNT);
	}

	public static synchronized HttpTransport getHttpTransport() {
		if (transport == null) {
			HttpTransport.setLowLevelHttpTransport(ApacheHttpTransport.INSTANCE);
			transport = GoogleTransport.create();
			GoogleHeaders headers = (GoogleHeaders) transport.defaultHeaders;
			headers.setApplicationName("google-calendarandroidsample-1.0");
			headers.gdataVersion = "2";
			AtomParser parser = new AtomParser();
			parser.namespaceDictionary = Namespace.DICTIONARY;
			transport.addParser(parser);

			if (!ContextService.inst.isApplicationContextLoaded()) {
				// desktop
				ClientLogin authenticator = new ClientLogin();
				authenticator.authTokenType = AUTH_TOKEN_TYPE;
				authenticator.username = ConfigService.inst.getValue(ConfigKey.FRANK_USERNAME);
				authenticator.password = ConfigService.inst.getValue(ConfigKey.FRANK_PASSWORD);
				try {
					authenticator.authenticate().setAuthorizationHeader(transport);
					return transport;
				} catch (Exception e) {
					Logger.inst.error(e);
					return null;
				}
			}
		}

		if (ContextService.inst.isApplicationContextLoaded()) {
			// phone
			return gotAccount(false);
		}
		return transport;
	}

	private static HttpTransport gotAccount(boolean tokenExpired) {
		Account account = getUserAccount();

		if (tokenExpired) {
			AccountManager.get(ContextService.inst.getApplicationContext()).invalidateAuthToken("com.google", AccountUtil.authToken);
		}
		return gotAccount(account);
	}

	private static HttpTransport gotAccount(final Account account) {

		final AccountManager manager = AccountManager.get(ContextService.inst.getApplicationContext());
		/*
		 * new Thread() {
		 * 
		 * @Override public void run() {
		 */
		try {
			final Bundle bundle = manager.getAuthToken(account, AUTH_TOKEN_TYPE, true, null, null).getResult();

			try {
				if (bundle.containsKey(AccountManager.KEY_INTENT)) {
					Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT);
					int flags = intent.getFlags();
					flags &= ~Intent.FLAG_ACTIVITY_NEW_TASK;
					intent.setFlags(flags);
					// startActivityForResult(intent,
					// REQUEST_AUTHENTICATE);
					ContextService.inst.getApplicationContext().startActivity(intent);
					// TODO wait till the activity is finished
					ThreadUtil.sleep(7000);
					gotAccount(false);

				} else if (bundle.containsKey(AccountManager.KEY_AUTHTOKEN)) {
					return authenticatedClientLogin(bundle.getString(AccountManager.KEY_AUTHTOKEN));
				}
			} catch (Exception e) {
				handleException(e);
			}
		} catch (Exception e) {
			handleException(e);
		}

		return null;
		/*
		 * } }.start();
		 */
	}

	private static HttpTransport authenticatedClientLogin(String authToken) {
		AccountUtil.authToken = authToken;
		((GoogleHeaders) transport.defaultHeaders).setGoogleLogin(authToken);
		return transport;
	}

	private static void handleException(Exception e) {
		Logger.inst.warning(e);
		if (e instanceof HttpResponseException) {
			HttpResponse response = ((HttpResponseException) e).response;
			int statusCode = response.statusCode;
			try {
				response.ignore();
			} catch (IOException e1) {
				Logger.inst.error(e1);
			}
			if (statusCode == 401 || statusCode == 403) {
				gotAccount(true);
				return;
			}
		}
	}

}
